@openrig/cli 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/daemon/assets/plugins/openrig-core/hooks/claude.json +11 -0
- package/daemon/assets/plugins/openrig-core/hooks/codex.json +14 -3
- package/daemon/assets/plugins/openrig-core/hooks/scripts/compaction-restore-bridge.cjs +28 -24
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/precompact-hook.mjs +72 -11
- package/daemon/assets/plugins/openrig-core/skills/queue-handoff/SKILL.md +62 -29
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts +32 -0
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js +154 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
- package/daemon/dist/db/migrations/044_queue_item_summary.d.ts +21 -0
- package/daemon/dist/db/migrations/044_queue_item_summary.d.ts.map +1 -0
- package/daemon/dist/db/migrations/044_queue_item_summary.js +25 -0
- package/daemon/dist/db/migrations/044_queue_item_summary.js.map +1 -0
- package/daemon/dist/domain/agent-activity-store.js +11 -0
- package/daemon/dist/domain/agent-activity-store.js.map +1 -1
- package/daemon/dist/domain/claude-compaction-enforcer.d.ts.map +1 -1
- package/daemon/dist/domain/claude-compaction-enforcer.js +69 -1
- package/daemon/dist/domain/claude-compaction-enforcer.js.map +1 -1
- package/daemon/dist/domain/daemon-version.d.ts +15 -0
- package/daemon/dist/domain/daemon-version.d.ts.map +1 -0
- package/daemon/dist/domain/daemon-version.js +28 -0
- package/daemon/dist/domain/daemon-version.js.map +1 -0
- package/daemon/dist/domain/node-cmux-service.d.ts +1 -0
- package/daemon/dist/domain/node-cmux-service.d.ts.map +1 -1
- package/daemon/dist/domain/node-cmux-service.js +29 -2
- package/daemon/dist/domain/node-cmux-service.js.map +1 -1
- package/daemon/dist/domain/queue-repository.d.ts +18 -0
- package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
- package/daemon/dist/domain/queue-repository.js +18 -0
- package/daemon/dist/domain/queue-repository.js.map +1 -1
- package/daemon/dist/domain/scope/scope-audit.d.ts +14 -2
- package/daemon/dist/domain/scope/scope-audit.d.ts.map +1 -1
- package/daemon/dist/domain/scope/scope-audit.js +95 -0
- package/daemon/dist/domain/scope/scope-audit.js.map +1 -1
- package/daemon/dist/domain/scope/types.d.ts +6 -0
- package/daemon/dist/domain/scope/types.d.ts.map +1 -1
- package/daemon/dist/domain/scope/types.js +8 -0
- package/daemon/dist/domain/scope/types.js.map +1 -1
- package/daemon/dist/domain/session-transport.d.ts +10 -0
- package/daemon/dist/domain/session-transport.d.ts.map +1 -1
- package/daemon/dist/domain/session-transport.js +153 -19
- package/daemon/dist/domain/session-transport.js.map +1 -1
- package/daemon/dist/domain/slices/slice-detail-projector.d.ts.map +1 -1
- package/daemon/dist/domain/slices/slice-detail-projector.js +10 -3
- package/daemon/dist/domain/slices/slice-detail-projector.js.map +1 -1
- package/daemon/dist/domain/types.d.ts +10 -0
- package/daemon/dist/domain/types.d.ts.map +1 -1
- package/daemon/dist/domain/types.js.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.d.ts +1 -0
- package/daemon/dist/domain/workspace/default-workspace-scaffold.d.ts.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js +25 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js.map +1 -1
- package/daemon/dist/routes/bundles.d.ts.map +1 -1
- package/daemon/dist/routes/bundles.js +1 -18
- package/daemon/dist/routes/bundles.js.map +1 -1
- package/daemon/dist/routes/health-summary.d.ts.map +1 -1
- package/daemon/dist/routes/health-summary.js +13 -2
- package/daemon/dist/routes/health-summary.js.map +1 -1
- package/daemon/dist/routes/queue.d.ts.map +1 -1
- package/daemon/dist/routes/queue.js +3 -0
- package/daemon/dist/routes/queue.js.map +1 -1
- package/daemon/dist/routes/scope-audit.d.ts.map +1 -1
- package/daemon/dist/routes/scope-audit.js +28 -1
- package/daemon/dist/routes/scope-audit.js.map +1 -1
- package/daemon/dist/routes/transport.d.ts.map +1 -1
- package/daemon/dist/routes/transport.js +22 -0
- package/daemon/dist/routes/transport.js.map +1 -1
- package/daemon/dist/startup.d.ts.map +1 -1
- package/daemon/dist/startup.js +15 -3
- package/daemon/dist/startup.js.map +1 -1
- package/dist/commands/auth.d.ts +11 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +145 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/config-init-workspace.d.ts.map +1 -1
- package/dist/commands/config-init-workspace.js +7 -4
- package/dist/commands/config-init-workspace.js.map +1 -1
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +23 -0
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/scope.d.ts.map +1 -1
- package/dist/commands/scope.js +64 -6
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +40 -7
- package/dist/commands/send.js.map +1 -1
- package/dist/daemon-lifecycle.d.ts +1 -0
- package/dist/daemon-lifecycle.d.ts.map +1 -1
- package/dist/daemon-lifecycle.js +35 -3
- package/dist/daemon-lifecycle.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/codex-auth.d.ts +124 -0
- package/dist/lib/codex-auth.d.ts.map +1 -0
- package/dist/lib/codex-auth.js +418 -0
- package/dist/lib/codex-auth.js.map +1 -0
- package/dist/lib/scope/scope-audit.d.ts +14 -2
- package/dist/lib/scope/scope-audit.d.ts.map +1 -1
- package/dist/lib/scope/scope-audit.js +95 -0
- package/dist/lib/scope/scope-audit.js.map +1 -1
- package/dist/lib/scope/templates.d.ts +9 -0
- package/dist/lib/scope/templates.d.ts.map +1 -1
- package/dist/lib/scope/templates.js +14 -1
- package/dist/lib/scope/templates.js.map +1 -1
- package/dist/lib/scope-templates/mission-brief.md +20 -0
- package/dist/lib/scope-templates/placeholder.md +8 -0
- package/dist/lib/scope-templates/proof.md +17 -0
- package/package.json +2 -1
- package/ui/dist/assets/index-CnqRX7A3.css +32 -0
- package/ui/dist/assets/index-CtL9jXFt.js +582 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-DMI6jeAX.css +0 -32
- package/ui/dist/assets/index-FQgCB6mC.js +0 -580
|
@@ -41,6 +41,17 @@
|
|
|
41
41
|
]
|
|
42
42
|
}
|
|
43
43
|
],
|
|
44
|
+
"PreCompact": [
|
|
45
|
+
{
|
|
46
|
+
"hooks": [
|
|
47
|
+
{
|
|
48
|
+
"type": "command",
|
|
49
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/skills/claude-compaction-restore/scripts/precompact-hook.mjs\"",
|
|
50
|
+
"timeout": 30
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
],
|
|
44
55
|
"PostCompact": [
|
|
45
56
|
{
|
|
46
57
|
"hooks": [
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "node \"${
|
|
8
|
+
"command": "node \"${PLUGIN_ROOT}/hooks/scripts/activity-relay.cjs\"",
|
|
9
9
|
"timeout": 5
|
|
10
10
|
}
|
|
11
11
|
]
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "node \"${
|
|
19
|
+
"command": "node \"${PLUGIN_ROOT}/hooks/scripts/activity-relay.cjs\"",
|
|
20
20
|
"timeout": 5
|
|
21
21
|
}
|
|
22
22
|
]
|
|
@@ -27,7 +27,18 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "command",
|
|
30
|
-
"command": "node \"${
|
|
30
|
+
"command": "node \"${PLUGIN_ROOT}/hooks/scripts/activity-relay.cjs\"",
|
|
31
|
+
"timeout": 5
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"PermissionRequest": [
|
|
37
|
+
{
|
|
38
|
+
"hooks": [
|
|
39
|
+
{
|
|
40
|
+
"type": "command",
|
|
41
|
+
"command": "node \"${PLUGIN_ROOT}/hooks/scripts/activity-relay.cjs\"",
|
|
31
42
|
"timeout": 5
|
|
32
43
|
}
|
|
33
44
|
]
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
-
// OpenRig Claude compaction restore bridge.
|
|
4
|
+
// OpenRig Claude compaction restore bridge (reader/deliverer).
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
6
|
+
// The per-seat pending marker is WRITTEN on PreCompact by the product-plugin
|
|
7
|
+
// writer skills/claude-compaction-restore/scripts/precompact-hook.mjs (which
|
|
8
|
+
// generates the restore packet and persists the real outputDir + operator
|
|
9
|
+
// message). This bridge READS that marker on SessionStart (matcher=compact)
|
|
10
|
+
// and UserPromptSubmit and injects ONE restore directive into Claude context
|
|
11
|
+
// via hookSpecificOutput.additionalContext. PostCompact is a cheap marker
|
|
12
|
+
// timestamp hook. OPR.0.4.1.09: resolve ONLY this seat's marker (never deliver
|
|
13
|
+
// another seat's restore state) and surface the per-seat restore-map pointer.
|
|
10
14
|
|
|
11
15
|
const fs = require("node:fs");
|
|
12
16
|
const os = require("node:os");
|
|
@@ -76,26 +80,21 @@ function readMarker(filePath) {
|
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
function findMarker(payload, env = process.env) {
|
|
79
|
-
|
|
83
|
+
// OPR.0.4.1.09 (never deliver wrong-seat state): resolve ONLY this seat's keyed marker.
|
|
84
|
+
// The previous fallback-to-newest handed a seat with NO marker the NEWEST marker on
|
|
85
|
+
// disk - which can be ANOTHER seat's (the reader-side parallel of the part-1 extra bug).
|
|
86
|
+
// No seat identity -> no marker; absence -> the loud JSONL fallback the restore prompt
|
|
87
|
+
// already describes, NEVER a wrong-seat guess.
|
|
80
88
|
const key = sessionKey(payload, env);
|
|
81
|
-
if (key)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs);
|
|
91
|
-
for (const candidate of candidates) {
|
|
92
|
-
const marker = readMarker(candidate.filePath);
|
|
93
|
-
if (marker) return marker;
|
|
94
|
-
}
|
|
95
|
-
} catch {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
89
|
+
if (!key) return null;
|
|
90
|
+
const marker = readMarker(path.join(markerDir(env), `${key}.json`));
|
|
91
|
+
if (!marker) return null;
|
|
92
|
+
// Defense-in-depth: refuse a keyed marker that DECLARES a different seat.
|
|
93
|
+
const declaredName = marker.data && typeof marker.data.sessionName === "string"
|
|
94
|
+
? marker.data.sessionName.trim()
|
|
95
|
+
: "";
|
|
96
|
+
if (declaredName && sanitizeKey(declaredName) !== key) return null;
|
|
97
|
+
return marker;
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
function writeMarker(marker) {
|
|
@@ -106,6 +105,7 @@ function buildRestoreContext(marker) {
|
|
|
106
105
|
const outputDir = firstString(marker.data.outputDir) || "/tmp/claude-compaction-restore";
|
|
107
106
|
const ack = firstString(marker.data.expectedAck) || "restored from packet at <path>; resumed at step <X>";
|
|
108
107
|
const postInstruction = firstString(marker.data.postCompactInstruction);
|
|
108
|
+
const restoreMapPath = firstString(marker.data.restoreMapPath);
|
|
109
109
|
const pieces = [
|
|
110
110
|
"OpenRig compaction restore packet is available for this Claude session.",
|
|
111
111
|
"This hook output is informational context, not the action request.",
|
|
@@ -113,6 +113,10 @@ function buildRestoreContext(marker) {
|
|
|
113
113
|
"OpenRig may send a later normal user message asking you to restore from this packet. Treat that later normal user message as the operator-authorized action request.",
|
|
114
114
|
`After restoration, reply with: ${ack}`,
|
|
115
115
|
];
|
|
116
|
+
if (restoreMapPath) {
|
|
117
|
+
// OPR.0.4.1.09: the per-seat restore-map pointer the marker carries.
|
|
118
|
+
pieces.push(`Per-seat restore map: ${restoreMapPath} — read it during restore.`);
|
|
119
|
+
}
|
|
116
120
|
if (postInstruction) {
|
|
117
121
|
pieces.push(`Operator post-compaction context: ${postInstruction}`);
|
|
118
122
|
}
|
|
@@ -41,6 +41,10 @@ function readInstructionFile(filePath) {
|
|
|
41
41
|
return fs.readFileSync(expanded, "utf8");
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function sanitizeKey(value) {
|
|
45
|
+
return value.replace(/[^a-zA-Z0-9_.@-]/g, "_");
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
function sessionKey(input) {
|
|
45
49
|
const raw = [
|
|
46
50
|
process.env.OPENRIG_SESSION_NAME,
|
|
@@ -51,13 +55,65 @@ function sessionKey(input) {
|
|
|
51
55
|
input.sessionName,
|
|
52
56
|
input.transcript_path ? path.basename(input.transcript_path, ".jsonl") : "",
|
|
53
57
|
].find((value) => typeof value === "string" && value.trim().length > 0) || "unknown-session";
|
|
54
|
-
return raw
|
|
58
|
+
return sanitizeKey(raw);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// OPR.0.4.1.09 (rev1-r2 hook-path leak fix): MUST match claude-compaction-enforcer.ts
|
|
62
|
+
// declaredSeatOf EXACTLY — a seat is authoritative ONLY inside a WELL-FORMED leading
|
|
63
|
+
// frontmatter fence (opened AND closed `---`); the body is NEVER scanned; malformed/absent
|
|
64
|
+
// frontmatter -> null (generic). Duplicated (not imported) because this hook is a standalone
|
|
65
|
+
// portable plugin asset that cannot import the compiled daemon TS; semantics are kept
|
|
66
|
+
// identical so the enforcer and hook paths refuse wrong-seat extras the same way.
|
|
67
|
+
function declaredSeatOf(content) {
|
|
68
|
+
const fm = /^\s*---\s*\n([\s\S]*?)\n---/.exec(content);
|
|
69
|
+
if (!fm) return null;
|
|
70
|
+
const m = /^[ \t]*(?:target[_-]?seat|seat|session(?:[_-]?name)?)[ \t]*:[ \t]*["']?([^"'\n#]+?)["']?[ \t]*$/im.exec(fm[1]);
|
|
71
|
+
return m ? m[1].trim() : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// OPR.0.4.1.09 (rev1-r2): resolve the seat-safe EXTRA-FILE CONTENT for
|
|
75
|
+
// postCompactInstruction, mirroring the enforcer resolvePostCompactExtra: (1) prefer the
|
|
76
|
+
// PER-SEAT extra post-compact-extra/<seat>.md; (2) else the GLOBAL messageFilePath. In
|
|
77
|
+
// EITHER case a file whose WELL-FORMED frontmatter declares a DIFFERENT seat is REFUSED
|
|
78
|
+
// (returns "") so a foreign-seat extra never leaks into the marker via the hook path
|
|
79
|
+
// (the enforcer path already refused it). Generic/this-seat/malformed -> inject.
|
|
80
|
+
function readSeatSafeExtraFile(input, globalFilePath) {
|
|
81
|
+
const seatKey = sessionKey(input);
|
|
82
|
+
const refusedIfForeign = (content) => {
|
|
83
|
+
const declared = declaredSeatOf(content);
|
|
84
|
+
return declared && sanitizeKey(declared) !== seatKey ? "" : content;
|
|
85
|
+
};
|
|
86
|
+
// 1. Per-seat extra preferred (seat-keyed path; still defensively seat-checked to match
|
|
87
|
+
// the enforcer, which refuses a per-seat file declaring a different seat).
|
|
88
|
+
const perSeatPath = path.join(getOpenRigHome(), "compaction", "post-compact-extra", `${seatKey}.md`);
|
|
89
|
+
if (fs.existsSync(perSeatPath)) {
|
|
90
|
+
return refusedIfForeign(fs.readFileSync(perSeatPath, "utf8"));
|
|
91
|
+
}
|
|
92
|
+
// 2. Global messageFilePath fallback, seat-checked.
|
|
93
|
+
if (!globalFilePath) return "";
|
|
94
|
+
const content = readInstructionFile(globalFilePath);
|
|
95
|
+
if (!content) return "";
|
|
96
|
+
return refusedIfForeign(content);
|
|
55
97
|
}
|
|
56
98
|
|
|
57
99
|
function pendingMarkerPath(input) {
|
|
58
100
|
return path.join(getOpenRigHome(), "compaction", "restore-pending", `${sessionKey(input)}.json`);
|
|
59
101
|
}
|
|
60
102
|
|
|
103
|
+
// OPR.0.4.1.09: pointer to this seat's per-seat post-compaction extra
|
|
104
|
+
// (compaction/post-compact-extra/<seat>.md), surfaced by the bridge reader.
|
|
105
|
+
// Returned ONLY when it EXISTS, so the marker never points at an unresolvable
|
|
106
|
+
// restoreMapPath; null otherwise.
|
|
107
|
+
function perSeatRestoreMapPath(input) {
|
|
108
|
+
const p = path.join(getOpenRigHome(), "compaction", "post-compact-extra", `${sessionKey(input)}.md`);
|
|
109
|
+
try {
|
|
110
|
+
fs.accessSync(p);
|
|
111
|
+
return p;
|
|
112
|
+
} catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
61
117
|
function writePendingRestoreMarker(input, parsed, restoreInstruction, customMessage) {
|
|
62
118
|
const markerPath = pendingMarkerPath(input);
|
|
63
119
|
fs.mkdirSync(path.dirname(markerPath), { recursive: true });
|
|
@@ -74,6 +130,8 @@ function writePendingRestoreMarker(input, parsed, restoreInstruction, customMess
|
|
|
74
130
|
expectedAck: "restored from packet at <path>; resumed at step <X>",
|
|
75
131
|
deliveredAt: null,
|
|
76
132
|
deliveryCount: 0,
|
|
133
|
+
// OPR.0.4.1.09: per-seat restore-map pointer (post-compact-extra/<seat>.md) or null.
|
|
134
|
+
restoreMapPath: perSeatRestoreMapPath(input),
|
|
77
135
|
};
|
|
78
136
|
fs.writeFileSync(markerPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
79
137
|
return markerPath;
|
|
@@ -86,7 +144,7 @@ function writePendingRestoreMarker(input, parsed, restoreInstruction, customMess
|
|
|
86
144
|
// enabled but restore text has not been written yet, use OpenRig's default
|
|
87
145
|
// instruction to load the canonical restore skill. Inline instructions and
|
|
88
146
|
// file-path content are both included when both are configured.
|
|
89
|
-
function readClaudeCompactionMessage() {
|
|
147
|
+
function readClaudeCompactionMessage(input) {
|
|
90
148
|
const configPath = path.join(getOpenRigHome(), "config.json");
|
|
91
149
|
let inline = "";
|
|
92
150
|
let filePath = "";
|
|
@@ -115,17 +173,20 @@ function readClaudeCompactionMessage() {
|
|
|
115
173
|
|
|
116
174
|
const parts = [];
|
|
117
175
|
if (inline && inline.length > 0) {
|
|
176
|
+
// Inline has no file/seat to declare; keep as-is.
|
|
118
177
|
parts.push(`Inline restore instruction:\n${inline}`);
|
|
119
178
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
179
|
+
// OPR.0.4.1.09 (rev1-r2): the FILE portion is SEAT-SAFE — per-seat extra preferred, a
|
|
180
|
+
// foreign-seat global refused (mirrors the enforcer). Checked even when messageFilePath
|
|
181
|
+
// is unset, because the per-seat extra is an independent mechanism (the enforcer also
|
|
182
|
+
// checks the per-seat path regardless of the global config).
|
|
183
|
+
try {
|
|
184
|
+
const fileText = readSeatSafeExtraFile(input, filePath);
|
|
185
|
+
if (fileText) {
|
|
186
|
+
parts.push(`Additional restore instruction file:\n${fileText}`);
|
|
128
187
|
}
|
|
188
|
+
} catch {
|
|
189
|
+
// Keep any inline instruction; unreadable extra files degrade quietly.
|
|
129
190
|
}
|
|
130
191
|
if (parts.length > 0) return parts.join("\n\n");
|
|
131
192
|
if (policyEnabled && !inlineConfigured && !filePathConfigured) {
|
|
@@ -147,7 +208,7 @@ try {
|
|
|
147
208
|
args.push(input.transcript_path);
|
|
148
209
|
}
|
|
149
210
|
|
|
150
|
-
const customMessage = readClaudeCompactionMessage();
|
|
211
|
+
const customMessage = readClaudeCompactionMessage(input);
|
|
151
212
|
|
|
152
213
|
const result = spawnSync("node", args, { encoding: "utf8" });
|
|
153
214
|
if (result.status !== 0) {
|
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: queue-handoff
|
|
3
|
-
description: Use when ending a turn, finishing a slice, blocked on another agent's work, or escalating to a human — durable work handoff via queue items so the system keeps moving across compactions, missed messages, and interruptions. Covers the hot-potato terminal-turn-rule (active work ends by passing the ball, not by going idle), default-nudge semantics, and when
|
|
3
|
+
description: Use when ending a turn, finishing a slice, blocked on another agent's work, or escalating to a human — durable work handoff via queue items so the system keeps moving across compactions, missed messages, and interruptions. Covers the hot-potato terminal-turn-rule (active work ends by passing the ball, not by going idle), default-nudge semantics, and when `--no-nudge` is appropriate for intentional cold park or human gate.
|
|
4
4
|
metadata:
|
|
5
5
|
openrig:
|
|
6
6
|
stage: factory-approved
|
|
7
|
-
last_verified: "2026-
|
|
7
|
+
last_verified: "2026-06-24"
|
|
8
8
|
distribution_scope: product-bound
|
|
9
9
|
source_evidence: |
|
|
10
|
-
Daemon-backed `rig queue` shipped in v0.2.0 (PL-004 Phase A) with handed-off-to / handed-off-from / state field shape. `rig queue` is canonical for new work; `rigx queue` is recovery-only fallback. The daemon enforces hot-potato strict-rejection at the API.
|
|
10
|
+
Daemon-backed `rig queue` shipped in v0.2.0 (PL-004 Phase A) with handed-off-to / handed-off-from / state field shape. `rig queue` is canonical for new work; `rigx queue` is recovery-only fallback. The daemon enforces hot-potato strict-rejection at the API. Body resynced from canonical 2026-06-24 (demo-blocker fix: corrected the default-nudge guidance — the default already nudges; the previously-described extra notify flag does not exist on the shipped CLI).
|
|
11
11
|
sibling_skills: []
|
|
12
12
|
transfer_test: pending
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
# Queue Handoff
|
|
16
16
|
|
|
17
|
-
> **CANONICAL SURFACE NOTE (2026-05-11)** — `rig queue` (daemon-backed SQLite) is the
|
|
18
|
-
> canonical surface for all substantive work routing. `rigx queue` (filesystem v0
|
|
19
|
-
> prototype) is **recovery-only fallback**; qitems written via `rigx queue` are
|
|
20
|
-
> invisible to daemon-backed reads and break fleet-wide routing discipline.
|
|
21
|
-
|
|
22
17
|
Durable work handoff via queue items. Lets the system keep moving
|
|
23
18
|
through compactions, missed messages, and interruptions by passing the
|
|
24
19
|
ball forward instead of leaving work suspended in chat or in-flight
|
|
@@ -71,27 +66,64 @@ every surface (CLI, MCP, future UI) inherits the same guarantee.
|
|
|
71
66
|
|---|---|---|
|
|
72
67
|
| `rig queue create` | yes | New qitem created from scratch |
|
|
73
68
|
| `rig queue handoff` | yes | Transactional close-as-handed-off + create-new |
|
|
74
|
-
| `rig queue handoff-and-complete` |
|
|
75
|
-
| `rigx queue handoff` (filesystem v0 prototype; **recovery-only fallback since 2026-05-11**) | yes | Legacy artifact; qitems invisible to daemon-backed reads. Use `rig queue handoff` for all new substantive work. |
|
|
76
|
-
|
|
77
|
-
**Footgun**:
|
|
78
|
-
|
|
79
|
-
`
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
a
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
69
|
+
| `rig queue handoff-and-complete` | yes | Atomic close + create-new; default nudge wakes the new owner |
|
|
70
|
+
| `rigx queue handoff` (filesystem v0 prototype; **recovery-only fallback since 2026-05-11**) | yes | Legacy artifact; qitems invisible to daemon-backed reads; deprecated with removal queued. Use `rig queue handoff` (daemon-backed) for all new substantive work. |
|
|
71
|
+
|
|
72
|
+
**Footgun**: `--no-nudge` accidentally added to a live-loop handoff.
|
|
73
|
+
The shipped 0.3.1 CLI nudges by default on every queue write surface
|
|
74
|
+
(`rig queue create`, `rig queue handoff`, AND `rig queue handoff-and-complete`).
|
|
75
|
+
The only suppression flag is `--no-nudge` — appropriate for intentional
|
|
76
|
+
cold park, human-gate signal, or a deliberate poll-driven workflow, but
|
|
77
|
+
NOT for live-loop handoffs where motion matters.
|
|
78
|
+
|
|
79
|
+
**Rule**: in a live loop, omit `--no-nudge` and trust the default.
|
|
80
|
+
`--no-nudge` is the opt-out, not the opt-in. If you find yourself
|
|
81
|
+
reaching for `--notify`, stop — that flag does not exist on the
|
|
82
|
+
shipped 0.3.1 CLI; you may be following a stale instruction that
|
|
83
|
+
inverted the default-nudge polarity.
|
|
84
|
+
|
|
85
|
+
## Queue-body hygiene (token + parse safety)
|
|
86
|
+
|
|
87
|
+
The qitem body is durable DATA the daemon stores and replays on every
|
|
88
|
+
`rig queue show <id>` / `--json` read. Keep it small and parse-safe — a
|
|
89
|
+
bloated or malformed body costs every future reader, not just the
|
|
90
|
+
recipient.
|
|
91
|
+
|
|
92
|
+
- **No large command output in bodies.** Do NOT paste `rig ps`/`--nodes`
|
|
93
|
+
dumps, big JSON blobs, full proof output, diffs, or transcript chunks
|
|
94
|
+
into a qitem body. **Link the artifact PATH** (e.g.
|
|
95
|
+
`missions/<m>/<slice>/proof.md`) or **summarize in prose**, then point
|
|
96
|
+
at the file for the detail. A pasted dump makes `rig queue show <id>
|
|
97
|
+
--json` huge — a second-order token bloat: bloated DATA living in the
|
|
98
|
+
queue, distinct from the command-default output bombs the token-burn
|
|
99
|
+
emergency pack covers. (Sensor: dev1-guard token-burn-flag 8ea201e4,
|
|
100
|
+
2026-06; founder-directed cure.)
|
|
101
|
+
- **Substantive bodies go through `--body-file`, not inline `--body`.**
|
|
102
|
+
For anything beyond a short line, write the body to a file and pass
|
|
103
|
+
`--body-file <path>` (or `-` for stdin). Inline `--body` with shell
|
|
104
|
+
metacharacters is fragile.
|
|
105
|
+
- **No raw backticks in bodies.** Backticks in an inline body are shell
|
|
106
|
+
command-substitution and corrupt the payload (or execute). If you need
|
|
107
|
+
code/command spans, use `--body-file`, or drop the backticks and write
|
|
108
|
+
the command in plain text.
|
|
109
|
+
|
|
110
|
+
Heuristic: if the thing you want to include is more than a few lines or
|
|
111
|
+
contains shell metacharacters (backticks, `$`, quotes, newlines-with-pipes),
|
|
112
|
+
it belongs in a file you LINK, not in the body you paste.
|
|
113
|
+
|
|
114
|
+
Product backstop (defense-in-depth, NOT a substitute for this discipline):
|
|
115
|
+
`rig queue show` oversized-body truncation/preview is tracked separately
|
|
116
|
+
as slice OPR.0.4.1.3. The behavioral rule here is the primary, durable
|
|
117
|
+
cure; the product truncation is the safety net.
|
|
118
|
+
|
|
119
|
+
## Failure modes (6; verbatim)
|
|
89
120
|
|
|
90
121
|
1. Agent ends a turn without a handoff, so the rig appears idle.
|
|
91
|
-
2. Agent creates a queue item
|
|
122
|
+
2. Agent creates a queue item with `--no-nudge` inside a live loop, intending suppression of attention but breaking immediate motion. `--no-nudge` is for intentional cold park / human gate, not for routine live-loop handoffs. The opposite footgun — adding a `--notify` flag that does not exist on the shipped 0.3.1 CLI — comes from following stale instructions; the default already nudges.
|
|
92
123
|
3. Queue item is too small and turns work into bureaucracy.
|
|
93
124
|
4. Queue item is too broad and loses ownership, proof, or closure criteria.
|
|
94
125
|
5. Human escalation happens in chat but not as a durable attention item.
|
|
126
|
+
6. Agent pastes a large command dump (ps/nodes, big JSON, proof blob) into the qitem body, bloating the stored DATA so every future `rig queue show --json` read is huge. Link the proof PATH or summarize in prose; substantive bodies go through `--body-file`; no raw backticks inline.
|
|
95
127
|
|
|
96
128
|
## Durable handoff field shape
|
|
97
129
|
|
|
@@ -102,16 +134,16 @@ Every qitem carries:
|
|
|
102
134
|
- `state` — one of: `pending | in-progress | done | blocked | failed | denied | canceled | handed-off`
|
|
103
135
|
- `closure_reason` + `closure_target` — set on terminal closure per hot-potato rule
|
|
104
136
|
|
|
105
|
-
The
|
|
106
|
-
`rig queue`
|
|
107
|
-
|
|
137
|
+
The fields are auditable across both `rigx queue` (config-layer) and
|
|
138
|
+
`rig queue` (daemon-shipped) surfaces. Watchdog policies and workflow
|
|
139
|
+
runtime project new owners off these fields.
|
|
108
140
|
|
|
109
141
|
## Two surfaces (same shape)
|
|
110
142
|
|
|
111
143
|
| Surface | Status | When to use |
|
|
112
144
|
|---|---|---|
|
|
113
145
|
| `rig queue ...` (daemon-shipped, v0.2.0) | Active host coordination surface | Daemon-backed PL-004 work; SQLite-canonical |
|
|
114
|
-
| `rigx queue ...` (
|
|
146
|
+
| `rigx queue ...` (config-layer dogfood) | Coexists with daemon | Workflows still operating on the temporary substrate coordination layer; legacy artifacts |
|
|
115
147
|
|
|
116
148
|
Default posture: prefer daemon `rig queue` for new work. If a
|
|
117
149
|
daemon-backed coordination command fails, debug the command/runtime/schema
|
|
@@ -119,4 +151,5 @@ edge directly — don't fall back to stale pre-upgrade assumptions.
|
|
|
119
151
|
|
|
120
152
|
## See also
|
|
121
153
|
|
|
122
|
-
- `
|
|
154
|
+
- `looping-workflows` skill — operating discipline for self-driving rig-shaped loops; queue-handoff is its current handoff substrate
|
|
155
|
+
- `intake-routing` skill — how raw signals enter the system and become routed work that flows through the queue
|
|
@@ -22,6 +22,7 @@ export declare class CodexRuntimeAdapter implements RuntimeAdapter {
|
|
|
22
22
|
private readThreadIdByPid;
|
|
23
23
|
private sleep;
|
|
24
24
|
private resolveHomeDirByPid;
|
|
25
|
+
private activityRelayPath?;
|
|
25
26
|
constructor(deps: {
|
|
26
27
|
tmux: TmuxAdapter;
|
|
27
28
|
fsOps: CodexAdapterFsOps;
|
|
@@ -33,6 +34,7 @@ export declare class CodexRuntimeAdapter implements RuntimeAdapter {
|
|
|
33
34
|
readThreadIdByPid?: (pid: number) => string | undefined;
|
|
34
35
|
resolveHomeDirByPid?: ResolveHomeDirByPid;
|
|
35
36
|
sleep?: (ms: number) => Promise<void>;
|
|
37
|
+
activityRelayPath?: string;
|
|
36
38
|
});
|
|
37
39
|
/**
|
|
38
40
|
* plugin-primitive Phase 3a slice 3.5 — ensure Codex feature flag.
|
|
@@ -49,6 +51,36 @@ export declare class CodexRuntimeAdapter implements RuntimeAdapter {
|
|
|
49
51
|
ensureCodexFeatureFlag(enabled: boolean, opts?: {
|
|
50
52
|
codexVersion?: string;
|
|
51
53
|
}): void;
|
|
54
|
+
/**
|
|
55
|
+
* OPR.0.4.1.10 FR-A — write the OpenRig activity hooks into Codex's config layer
|
|
56
|
+
* (`~/.codex/config.toml` inline `[hooks]`) so an OpenRig-launched Codex seat is
|
|
57
|
+
* hook-PRIMARY from clean shipped config. Idempotent managed-block upsert for the
|
|
58
|
+
* four events SessionStart / UserPromptSubmit / Stop / PermissionRequest; each
|
|
59
|
+
* command is `node "<activityRelayPath>"` (the daemon's OWN shipped relay, FR-B —
|
|
60
|
+
* cwd-independent, version-matched, NOT `${PLUGIN_ROOT}` nor a per-cwd copy). Also
|
|
61
|
+
* pins `[features].hooks = true` (canonical key; the deprecated `codex_hooks` alias
|
|
62
|
+
* is intentionally NOT used here). Trust is granted at launch by the hook_trust_gate
|
|
63
|
+
* auto-clear (dismissCodexInteractiveGates → "2" Trust all and continue, verified on
|
|
64
|
+
* Codex 0.139). The relay inherits the seat's OPENRIG_* env from the tmux session.
|
|
65
|
+
*
|
|
66
|
+
* Fail-safe: skips + warns when the relay asset is missing — never writes a hook that
|
|
67
|
+
* points at a nonexistent script. Verified-firsthand (Codex 0.139, dev1-qa AC-2 proof):
|
|
68
|
+
* on the OpenRig-managed launch path — managed inline hooks + trusted + the relay env
|
|
69
|
+
* delivered into the seat (OPENRIG_URL + OPENRIG_ACTIVITY_HOOK_TOKEN + session/node/runtime)
|
|
70
|
+
* — all four events, SessionStart included, deliver as runtime_hook activity. Without the
|
|
71
|
+
* relay env the hooks are still trusted/visible but no activity rows land. (A bare/manual
|
|
72
|
+
* codex TUI launch lacks that context and may not deliver SessionStart — not how OpenRig
|
|
73
|
+
* launches seats.)
|
|
74
|
+
*/
|
|
75
|
+
ensureCodexActivityHooks(): void;
|
|
76
|
+
/**
|
|
77
|
+
* OPR.0.4.1.10 B3 — durable disable. When runtime.codex.hooks_enabled is false, strip the
|
|
78
|
+
* OpenRig-managed activity-hooks sentinel block from ~/.codex/config.toml so a seat that was
|
|
79
|
+
* previously provisioned with hooks does not keep firing them after the operator disables.
|
|
80
|
+
* Removes ONLY the managed block — preserves any user-owned hooks and leaves [features].hooks
|
|
81
|
+
* (the Codex 0.139 default) intact. Idempotent; no-op when the config or the block is absent.
|
|
82
|
+
*/
|
|
83
|
+
removeCodexActivityHooks(): void;
|
|
52
84
|
listInstalled(binding: NodeBinding): Promise<InstalledResource[]>;
|
|
53
85
|
project(plan: ProjectionPlan, binding: NodeBinding): Promise<ProjectionResult>;
|
|
54
86
|
deliverStartup(files: ResolvedStartupFile[], binding: NodeBinding): Promise<StartupDeliveryResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-runtime-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/codex-runtime-adapter.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EACV,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAChD,iBAAiB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,eAAe,EAC3E,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AAKtC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACxD,QAAQ,CAAC,OAAO,WAAW;IAC3B,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,aAAa,CAA8D;IACnF,OAAO,CAAC,iBAAiB,CAAsC;IAC/D,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,mBAAmB,CAAsB;
|
|
1
|
+
{"version":3,"file":"codex-runtime-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/codex-runtime-adapter.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EACV,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAChD,iBAAiB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,eAAe,EAC3E,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AAKtC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACxD,QAAQ,CAAC,OAAO,WAAW;IAC3B,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,aAAa,CAA8D;IACnF,OAAO,CAAC,iBAAiB,CAAsC;IAC/D,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,mBAAmB,CAAsB;IAKjD,OAAO,CAAC,iBAAiB,CAAC,CAAS;gBAEvB,IAAI,EAAE;QAChB,IAAI,EAAE,WAAW,CAAC;QAClB,KAAK,EAAE,iBAAiB,CAAC;QACzB,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC5E,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;QACxD,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;QAC1C,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACtC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B;IAUD;;;;;;;;;;;OAWG;IACH,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAehF;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,wBAAwB,IAAI,IAAI;IAmBhC;;;;;;OAMG;IACH,wBAAwB,IAAI,IAAI;IAY1B,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAWjE,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA0B9E,cAAc,CAAC,KAAK,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAgDlG,aAAa,CACjB,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,8BAA8B,EAAE,UAAU,CAAA;KAAE,GAC3G,OAAO,CAAC,mBAAmB,CAAC;IAkG/B,OAAO,CAAC,wBAAwB;IAW1B,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;YAqBlD,iCAAiC;YAiCjC,4BAA4B;IAuC1C,sBAAsB,CAAC,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAI9D,OAAO,CAAC,YAAY;IA2CpB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,oBAAoB;IAe5B;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,kBAAkB;YAUZ,oBAAoB;YAsBpB,kBAAkB;IAsGhC,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,oBAAoB;CAO7B;AAwDD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAO3D"}
|